#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <getopt.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sqlite3.h>
#include <libgen.h>

#define TABLE_NAME       "RPI_num1"

int         g_sigstop = 0;
char        *buftok[4];
static int  count=0;
int         rc=-1;
sqlite3     *db;
char        *zErrMsg=0;
char        write_buffer2[100];
int         iTableExist=0;
double      current_time;
double      last_time=0;
struct      tm* st;
struct      timeval tv;     


double gettime(char *data_time);
int get_temperature(float *T);
int socketconnected(int sockfd);
int client_init(int port, char *serv_ip);
static int sendata2_callback(void *data,int argc,char **argv, char **azColName);
int sendata2(int sockfd,char *table_name,int count);
int sendata(int sockfd,char *buftok[]);
int sqlite_table_exist(char *table_name);
static int table_exist_callback(void *data,int argc,char **argv,char **azColName);
static int callback_row_count(void *NotUsed, int argc,char **argv,char **azColName);
int table_row_count(char *table_name);
int sqlite_delete(int id,char *table_name);
void sqlite_insert(char *buftok[],char *table_name);
void sqlite_create_table(char *table_name);
void sqlite_init(void);
static int callback(void *NotUsed,int argc,char **argv,char **azColName);
void signal_stop(int signum);
void syslog(const char *ms, ...);



void print_usage(char *progname)
{
	printf("%s usage:\n",progname);
	printf("-i(--ipaddr):spceify server IP address\n");
	printf("-p(--port):spceify server port.\n");
	printf("-t(--set_time):RPI temperature interval time\n");
	printf("-d(--daemon):run background\n");
	printf("-h(--help):printf this help information.\n");
	return;
}

int main(int argc,char *argv[])
{
	float                   T=0;
	int                     ch;
	int                     rv=-1;
	int                     port=0;
	int                     connfd=-1;
	int                     daemon_run=0;
	int                     con_status=1;
	int                     set_time=0;
	char                    count_buffer[20];
	char                    temp_buffer[50];
	char                    da_time[50];
	double                  current_time=0;
	double                  last_time=0;
	char                    *programe_name;
	char                    *serv_ip=NULL;
	struct                  sigaction sigact;
	struct                  sigaction sigign;
	struct                  sockaddr_in serv_addr;
	struct                  option opts[]={
		{"ipaddr",required_argument,NULL,'i'},
		{"port",required_argument,NULL,'p'},
		{"interv_time",required_argument,NULL,'t'},
		{"daemon",no_argument,NULL,'d'},
		{"help",no_argument,NULL,'h'},
		{0,0,0,0}
	};

	while((ch=getopt_long(argc,argv,"i:p:t:dh",opts,NULL))!=-1)
	{
		switch(ch)
		{
			case 'i':
				serv_ip=optarg;
				break;
			case 'p':
				port=atoi(optarg);
				break;
	         	case 't':
				set_time=atoi(optarg);
				break;
			case 'd':
				daemon_run=1;
				break;
			case 'h':
				print_usage(argv[0]);
				return 0;
		}
	}

	if(!serv_ip || !port)
	{
		print_usage(argv[0]);
		return -1;
	}

	if(daemon_run)
	{
		if(daemon(0,0))
		{
			printf("Running daemon failure:%s\n",strerror(errno));
		}
		printf("Running daemon successfully!\n");
	}


	sigemptyset(&sigign.sa_mask);
	sigign.sa_flags=0;
	sigign.sa_handler=SIG_IGN;

	sigemptyset(&sigact.sa_mask);
	sigign.sa_flags=0;
	sigign.sa_handler=signal_stop;

	sigaction(SIGUSR1,&sigact,0);
	sigaction(SIGUSR2,&sigact,0);

	sqlite_init();
	if(sqlite_table_exist(TABLE_NAME)==0)
	{
		sqlite_create_table(TABLE_NAME);
	}
	count=table_row_count(TABLE_NAME);

	gettimeofday(&tv,NULL);
	current_time=tv.tv_sec;

	while(!g_sigstop)
	{
		sleep(set_time);
		gettimeofday(&tv,NULL);
		last_time=tv.tv_sec;

		connfd=client_init(port,serv_ip);                                  
		if(connfd<0)
		{                                            
			printf("sock_fd failure:%s\n",strerror(errno));
			con_status=0;
		}

		if(socketconnected(connfd)==0)                          
		{                                                       
			con_status=0;                   
		}

		if((last_time-current_time)>=set_time)
		{
			if((rv=get_temperature(&T))<0)
			{
				printf("Get temperature failure: %s\n",strerror(errno));
				return -2;	
			}

			 last_time=gettime(da_time);
			 current_time=last_time;
			 memset(count_buffer,0,sizeof(count_buffer));
			 snprintf(count_buffer,sizeof(count_buffer),"%d",(count+1));
			 memset(temp_buffer,0,sizeof(temp_buffer));
			 snprintf(temp_buffer,sizeof(temp_buffer),"%.3f",T);
			 buftok[0]=count_buffer;
			 buftok[1]="RPI_num1";
			 buftok[2]=da_time;
			 buftok[3]=temp_buffer;
			 buftok[4]="\n";

			if(con_status)
			{
				if(count>0)
				{
					while(count)
					{
						sqlite_init();
						sendata2(connfd,TABLE_NAME,count);
						sleep(1);
						sqlite_delete(count,TABLE_NAME);
						count--;
					}
					printf("The table data is null!\n");
				}

				else
				{
					sendata(connfd,buftok);
				}
			}
			else
			{
				connfd=client_init(port,serv_ip);
				if(connfd < 0)
				{
					printf("Client connect server failure1:%s\n",strerror(errno));
					sqlite_init();
					count=table_row_count(TABLE_NAME);

					con_status=0;
					sqlite_insert(buftok,TABLE_NAME);
					count++;
					close(connfd);
				}
				else
				{
					con_status=1;
					if(sendata(connfd,buftok)<0)
					{
						sqlite_init();
						count=table_row_count(TABLE_NAME);
						sqlite_insert(buftok,TABLE_NAME);
						count++;
						close(connfd);
					}
				}
			}	
		}
	}
	return 0;
}


void signal_stop(int signum)
{
	if(SIGUSR1 == signum)
	{
		printf("signum SIGUSR1 detected\n");
	}
	else if(SIGUSR2 == signum)
	{
		printf("signum SIGUSR2 detected\n");
	}
	g_sigstop = 1;
}


int client_init(int port,char *serv_ip)
{
	int         con_fd=-1;
	int         rv=-1;
	struct      sockaddr_in serv_addr;

	con_fd=socket(AF_INET,SOCK_STREAM,0);

	if(con_fd<0)
	{
		printf("Create socket failure: %s\n",strerror(errno));
		return -1;
	}

	printf("Create socket[%d] successfully!\n",con_fd);

	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_port=htons(port);
	inet_aton(serv_ip,&serv_addr.sin_addr);

	if(con_fd>=0)
	{
		rv=connect(con_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
		if(rv<0)
		{
			printf("Connect to server[%s:%d] failure: %s\n",serv_ip,port,strerror(errno));
			return -2;
		}
		printf("Connect to server[%s:%d] successfully!\n",serv_ip,port);
	}
	return con_fd;
}

double gettime(char *data_time)
{
	time_t timep;

	time(&timep);
	st=gmtime(&timep);
	memset(data_time,0,sizeof(data_time));
	snprintf(data_time,50,"%04d-%02d-%02d %02d:%02d:%02d",(1900+st->tm_year),(1+st->tm_mon),st->tm_mday,(st->tm_hour+8),st->tm_min,st->tm_sec);

	return last_time;
}




static int sendata2_callback(void *data,int argc,char **argv, char **azColName)
{
	memset(write_buffer2,0,sizeof(write_buffer2));
	snprintf(write_buffer2,100,"%s/%s/%s",argv[1],argv[2],argv[3]);
	printf("write_buffer2:%s\n",write_buffer2);
	return 0;
}




int sendata2(int sockfd,char *table_name,int count)
{
	int  write_rv2 = -1;
	char sendata_buffer2[512];
	memset(sendata_buffer2,0,sizeof(sendata_buffer2));
	snprintf(sendata_buffer2,512,"select * from %s limit 1 offset %d;",table_name,(count-1));

	rc=sqlite3_exec(db,sendata_buffer2,sendata2_callback,0,&zErrMsg);

	if(rc != SQLITE_OK)
	{
		printf("sendata_buffer2 failure:%d %s\n",rc,zErrMsg);
		sqlite3_free(zErrMsg);
		exit(0);
	}

	write_rv2=write(sockfd,write_buffer2,strlen(write_buffer2));
	if(write_rv2<0)
	{
		printf("Send data to server failure:%s\n",strerror(errno));
		return -1;
	}
	printf("Send data2 to server successfully!\n");
	syslog("Send data2 to server successfully!\n");
	return 0;
}



int sendata(int sockfd,char *buftok[])
{
	int  write_rv1 = -1;
	char sendata_buffer1[100];
	memset(sendata_buffer1,0,sizeof(sendata_buffer1));
	snprintf(sendata_buffer1,100,"%s/%s/%s",buftok[1],buftok[2],buftok[3]);

	write_rv1=write(sockfd,sendata_buffer1,strlen(sendata_buffer1));
	if(write_rv1<0)
	{
		printf("Send data to server failure:%s\n",strerror(errno));
		return -1;
	}
	printf("Send data1 to server successfully!\n");
	return 0;
}




int sqlite_table_exist(char *table_name)
{
	char table_exist[512];
	memset(table_exist,0,sizeof(table_exist));
	snprintf(table_exist,512,"SELECT COUNT(*) from sqlite_master where type='table' and name ='%s';",table_name);

	rc=sqlite3_exec(db,table_exist,table_exist_callback,0,&zErrMsg);
	if(rc != SQLITE_OK)
	{
		printf("sqlite_table_exist error:%s\n",zErrMsg);
		sqlite3_free(zErrMsg);
		exit(0);
	}

	if(iTableExist)
	{
		printf("%s is exist!\n",table_name);
		syslog("%s is exist!\n",table_name);
		return iTableExist;
	}
	else
	{
		return iTableExist;
	}
}




static int table_exist_callback(void *data,int argc,char **argv,char **azColName)
{
	if(1==argc)
	{
		iTableExist=atoi(*(argv));
	}
	return 0;
}




static int callback_row_count(void *NotUsed, int argc,char **argv,char **azColName)
{
	count=atoi(argv[0]);
	return 0;
}



int table_row_count(char *table_name)
{
	char row_count[100];
	memset(row_count,0,sizeof(row_count));
	snprintf(row_count,128,"SELECT COUNT(*) from %s;",table_name);

	rc=sqlite3_exec(db,row_count,callback_row_count,0,&zErrMsg);
	if(rc != SQLITE_OK)
	{
		printf("table_row_count error: %s\n",zErrMsg);
		sqlite3_free(zErrMsg);
	}
	else
	{
		return count;
	}
}




int sqlite_delete(int id,char *table_name)
{
	char sql_delete[100];
	memset(sql_delete,0,sizeof(sql_delete));
	snprintf(sql_delete,100,"DELETE from %s where ID=%d;SELECT * from %s;",table_name,count,table_name);

	rc=sqlite3_exec(db,sql_delete,0,0,&zErrMsg);
	if(rc != SQLITE_OK)
	{
		fprintf(stderr,"Sqlite_delete error: %s\n",zErrMsg);
		sqlite3_free(zErrMsg);
		return -1;
	}
	else
	{
		return 0;
	}
}




void sqlite_insert(char *tokbuf[],char *table_name)
{
	char sql_buffer[512];
	char *ID=tokbuf[0];
	char *SN=tokbuf[1];
	char *DATIME=tokbuf[2];
	char *TEMPERATURE=tokbuf[3];

	memset(sql_buffer,0,sizeof(sql_buffer));
	printf("Insert data to table %s:%s/%s/%s/%s\n",TABLE_NAME,tokbuf[0],tokbuf[1],tokbuf[2],tokbuf[3]);

	snprintf(sql_buffer,512,"INSERT INTO %s VALUES ('%s','%s','%s','%s');",table_name,ID,SN,DATIME,TEMPERATURE);

	rc=sqlite3_exec(db,sql_buffer,callback,0,&zErrMsg);
	if(rc != SQLITE_OK)
	{
		printf("Sqlite_insert fuilure:%s\n",zErrMsg);
		sqlite3_free(zErrMsg);
	}
	else
	{
		printf("Last data insert table successfully\n");
		syslog("Last data insert table successfully\n");
	}
	return;
}



void sqlite_create_table(char *table_name)
{
	char create_table[512];

	memset(create_table,0,sizeof(create_table));
	snprintf(create_table,512,"CREATE TABLE %s(ID CHAR(10),SN CHAR(10),DATIME CHAR(50),TEMPERATURE CHAR(50));",table_name);

	rc=sqlite3_exec(db,create_table,callback,0,&zErrMsg);
	if(rc != SQLITE_OK)
	{
		printf("Sqlite_create_table fuilure:%s\n",zErrMsg);
		sqlite3_free(zErrMsg);
		exit(0);
	}
	else
	{
		printf("Table created successfully!\n");
		syslog("Table created successfully!\n");
	}
	return;
}




static int callback(void *NotUsed,int argc,char **argv,char **azColName)
{
	int i;
	for(i=0;i<argc;i++)
	{
		printf("%s = %s\n",azColName[i],argv[i] ? argv[i] : "NULL");
	}
	printf("\n");
	return 0;
}



void sqlite_init(void)
{
	rc=sqlite3_open("RPI_temperature1.db",&db);
	if(rc)
	{
		printf("Can't open database:%s\n",sqlite3_errmsg(db));
		exit(0);
	}
	else
	{
		printf("Opened database successfully!\n");
		syslog("Opened database successfully!\n");
	}
}


int socketconnected(int sockfd)
{
	struct            tcp_info info;
	int               len=sizeof(info);

	if(sockfd<=0)
	{
		printf("Sockfd is error!\n");
		return 0;
	}
	getsockopt(sockfd,IPPROTO_TCP,TCP_INFO,&info,(socklen_t *)&len);
	if(info.tcpi_state == 1)           //TCP_ESTABLISHED
	{
		printf("Server connected!\n");
		return 1;
	}
	else
	{
		printf("Server disconnected!\n");
		return 0;
	}
}

int get_temperature(float *T)
{
	int               fd=-1;
	int               found=0;
	char              buf[128];
	char              *ptr=NULL;
	char              chip_sn[32];
	char              w1_path[64]="/sys/bus/w1/devices/";
	DIR               *dirp=NULL;
	struct            dirent *direntp=NULL;

	dirp=opendir(w1_path);
	if(!dirp)
	{
		printf("Open folder failure: %s\n",strerror(errno));
		return -1;
	}

	while(NULL !=(direntp=readdir(dirp)))
	{ 
		if(strstr(direntp->d_name, "28-"))
		{
			strncpy(chip_sn,direntp->d_name,sizeof(chip_sn));
			found=1;
		}

	}

	closedir(dirp);

	if(!found)
	{
		printf("Can not find ds18b20 chipset\n");
		return -2;
	}

	strncat(w1_path,chip_sn,sizeof(w1_path)-strlen(w1_path));
	strncat(w1_path,"/w1_slave",sizeof(w1_path)-strlen(w1_path));

	if((fd=open(w1_path,O_RDONLY))<0)
	{
		printf("Open file failure: %s\n",strerror(errno));
		return -3;
	}

	memset(buf,0,sizeof(buf));

	if(read(fd,buf,sizeof(buf))<0)
	{
		printf("Read data from fd=%d failure: %s\n",fd,strerror(errno));
		return -4;
	}

	ptr=strstr(buf,"t=");
	if(!ptr)
	{
		printf("Can not find t= \n");
		return -5;
	}

	ptr +=2;
	*T=atof(ptr)/1000;
	syslog("The temperature is %.3f\n",&T);
	close(fd);
	return 0;
}



void syslog(const char *ms, ...)
{
	char    wzLog[1024];
	char    buffer[2049];
	char    time_buf[1024];
	va_list args;

	memset(wzLog,0,sizeof(wzLog));
	memset(buffer,0,sizeof(buffer));
	va_start(args,ms);
	vsprintf(wzLog,ms,args);
	va_end(args);

	gettime(time_buf);

	snprintf(buffer,sizeof(buffer),"%s %s\n",time_buf,wzLog);
	FILE* file = fopen("client_syslog.log","a+");
	fwrite(buffer,1,strlen(buffer),file);
	fclose(file);
	return;
}

